package com.student;

import java.sql.*;
import java.util.Arrays;


/**
 * 为了在以后的大型项目中使用更加方便，层次更加清晰，对JDBC要进行一个分层处理
 *
 * DAO(Data Access Object) 数据访问对象模式
 *   实体类
 *     POJO 简单java对象
 *       一般表示实体，类中一般只有属性和访问器，也可以有构造方法，一般没有其他的普通方法
 *     一个 POJO 对象被持久化之后就是 PO 持久化对象
 *        一个java的POJO类的对象被写入到表中，形成一条数据
 *     使用POJO进行传递，过程中就是 DTO  数据传输对象
 *        把java的POJO类的对象写入表的过程中，就是一个数据传输对象
 *     最后把POJO用来做数据的展示 就是 VO 视图对象
 *        存也存完了，从数据表中获取的每条数据都是一个POJO对象，就是视图对象
 *   DAO接口
 *     定义了当前逻辑下的所有需要执行的内容的标准。
 *     如果为了让程序更加健壮，扩展性更强，需要写接口
 *     如果只是为了一个单一逻辑，也可以没有
 *
 *   DAO接口实现类
 *     根据具体的实际情况实现接口的抽象方法，进行定义
 *
 *
 */

public class AddDataToStudent {



    public void addStudent() throws SQLException {

        Connection conn = null;
        PreparedStatement ps = null;

        try {
            //1.加载数据库驱动,从mysql厂商提供的驱动包中加载这个Driver类，以便可以与Mysql进行连接
            Class.forName("com.mysql.jdbc.Driver");

            //2.建立mysql的连接
            //  连接的语法  <协议>:<子协议>://<ip>:<port>
            //  jdbc:mysql://localhost:3306
            conn = DriverManager.getConnection(
                    "jdbc:mysql://localhost:3306/bigdata",
                    "root",
                    "root");
            //比较适合连接数据库时所需的属性比较多的情况使用
//            Properties properties = new Properties();
//            properties.put("user","root");
//            properties.put("passwprd","root");
//            DriverManager.getConnection("jdbc:mysql://localhost:3306/bigdata",properties);

            //3.使用该连接操作数据
            //  Statement是操作数据库的接口，直接使用也可以，可能会出现一些问题
            //  select * from student where username='dxx' and password='xxx' or 1 = 1  sql注入漏洞
//            Statement statement = conn.createStatement();
            //预处理sql语句，某些参数以问号形式体现，直接编译，编译之后可以传参
            ps = conn.prepareStatement("insert into student values(?,?,?)");

            ps.setInt(1,1001);
            ps.setString(2,"李琪");
            ps.setInt(3,20);

            //4.执行sql预处理语句
            //  增删改查的所有语句都能执行，如果执行的是查询语句返回true，如果执行的是增删改语句返回false
            //  比较麻烦，需要判断true和false 使用单独的方法进行处理，一般不用
//            ps.execute();

            //  针对查询可以直接调用这个方法，返回一个 ResultSet 结果集
//            ps.executeQuery();
            //  针对增删改可以直接调用这个方法，返回受影响行数
            int count = ps.executeUpdate();

            if(count==1){
                System.out.println("添加成功");
            }else{
                System.out.println("添加失败");
            }

        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            //5.关闭连接  后使用的先关闭
            if(null!=ps){
                ps.close();
            }

            if(null!=conn){
                conn.close();
            }
        }


    }


    public void selectStudent() throws SQLException {

        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;

        try{
            Class.forName("com.mysql.jdbc.Driver");

            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/bigdata", "root", "root");

            ps = conn.prepareStatement("select * from student");

            rs = ps.executeQuery();


            //获取与数据库连接的元数据信息
            DatabaseMetaData dbmd = conn.getMetaData();

            System.out.println("url:"+dbmd.getURL());

            System.out.println("username:"+dbmd.getUserName());

            System.out.println("isReadOnly:"+dbmd.isReadOnly());

            System.out.println("db:"+dbmd.getDatabaseProductName());

            System.out.println("version:"+dbmd.getDatabaseProductVersion());

            System.out.println("driver:"+dbmd.getDriverName());

            System.out.println("driverVersion:"+dbmd.getDriverVersion());

            System.out.println("++++++++++++++++++++++++++++++++++++++++++++++++++++++");


            //获取结果集中的元数据信息
            ResultSetMetaData md = rs.getMetaData();

            String columnName = md.getColumnName(1);
            System.out.println(columnName);

            int columnCount = md.getColumnCount();
            System.out.println(columnCount);

            String columnTypeName = md.getColumnTypeName(2);
            System.out.println(columnTypeName);

            int nullable = md.isNullable(3);
            System.out.println(nullable);

            boolean autoIncrement = md.isAutoIncrement(1);
            System.out.println(autoIncrement);

            //获取结果集中的真实数据信息
            while(rs.next()){
                int stuId = rs.getInt("stuId");
                String stuName = rs.getString("stuName");
                int stuAge = rs.getInt(3);
                System.out.println("id:"+stuId+",name:"+stuName+",age:"+stuAge);
                System.out.println("=====================================");
            }

        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if(null!=rs){
                rs.close();
            }
            if(null!=ps){
                ps.close();
            }

            if(null!=conn){
                conn.close();
            }
        }
    }


    public void addMoreStudent() throws SQLException {

        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;

        try {
            Class.forName("com.mysql.jdbc.Driver");

            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/bigdata", "root", "root");

            //第一种方式：直接使用语句添加多条
//            ps = conn.prepareStatement("insert into student values(1002,\"冯浩翔\",20)," +
//                    "(1003,\"杨绅\",20),(1004,\"张仁贵\",20)");


            //第二种方式：使用同一个预处理语句，分别设置不同的值执行操作
//            ps = conn.prepareStatement("insert into student values(?,?,?)");
//
//            ps.setInt(1,1005);
//            ps.setString(2,"于效东");
//            ps.setInt(3,20);
//
//            int count = ps.executeUpdate();
//
//            System.out.println("添加了"+count+"条数据");
//
//            ps.setInt(1,1006);
//            ps.setString(2,"郭苏林");
//            ps.setInt(3,20);
//
//            int count1 = ps.executeUpdate();
//
//            System.out.println("添加了"+count1+"条数据");

            //第三种方式：
            // 3.1 使用Statement进行批处理
//            Statement statement = conn.createStatement();
//            statement.addBatch("insert into student values(1007,\"张志雪\",20)");
//            statement.addBatch("insert into student values(1008,\"李明跃\",20)");
//
//            int[] ints = statement.executeBatch();
//
//            System.out.println(Arrays.toString(ints));


            // 3.2 使用 PreparedStatement 进行预处理
            ps = conn.prepareStatement("insert into student values(?,?,?)");

            // 如果数据有规律 ，可以使用循环，如果没有规律，每条数据分别设置
            for (int i = 1100; i < 1102; i++) {
                ps.setInt(1,i);
                ps.setString(2,"tom");
                ps.setInt(3,20);

                ps.addBatch();
            }

            int[] ints = ps.executeBatch();
            System.out.println(Arrays.toString(ints));


        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if(null!=rs){
                rs.close();
            }
            if(null!=ps){
                ps.close();
            }

            if(null!=conn){
                conn.close();
            }
        }
    }

    public void useTransaction() throws SQLException {
        Connection conn = null;
        PreparedStatement ps_less = null;
        PreparedStatement ps_more = null;
        ResultSet rs = null;

        try {
            Class.forName("com.mysql.jdbc.Driver");

            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/bigdata", "root", "root");

            //取消自动提交
            conn.setAutoCommit(false);

            ps_less = conn.prepareStatement("update student set stuAge=stuAge-50 where stuId=? ");
            ps_less.setInt(1,2);
            int lessCount = ps_less.executeUpdate();

            //可以设置保存点，也可以回滚到具体的保存点
            Savepoint savepoint = conn.setSavepoint();
            conn.rollback(savepoint);


            ps_more = conn.prepareStatement("update student set stuAge=stuAge+50 where stuId=? ");
            ps_more.setInt(1,4);
            int moreCount = ps_more.executeUpdate();


            //如果都是 1 表示成功了
            if(lessCount==1 && moreCount==1){
                conn.commit();
                System.out.println("续命成功");
            }

        }catch (Exception e){
            conn.rollback();
        }finally {
            if(null!=rs){
                rs.close();
            }

            if(null!=ps_less){
                ps_less.close();
            }

            if(null!=ps_more){
                ps_more.close();
            }

            if(null!=conn){
                conn.close();
            }
        }
    }

    public static void main(String[] args) throws SQLException {
        new AddDataToStudent().useTransaction();
    }

}
